package com.fzf.org.toolkit;

import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
import org.bouncycastle.crypto.params.Argon2Parameters;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class Argon2PasswordEncoder {

    // Argon2 参数配置（可根据实际需要调整）
    private static final int SALT_LENGTH = 16;
    private static final int HASH_LENGTH = 32;
    private static final int ITERATIONS = 3;
    private static final int MEMORY_KB = 65536; // 64 MB
    private static final int PARALLELISM = 1;

    private static final SecureRandom secureRandom = new SecureRandom();

    /**
     * 对明文密码进行哈希
     */
    public static String encode(String rawPassword) {
        byte[] salt = new byte[SALT_LENGTH];
        secureRandom.nextBytes(salt);

        byte[] hash = hashPassword(rawPassword.getBytes(StandardCharsets.UTF_8), salt);

        // 将 salt 和 hash 一起编码为 Base64，拼接起来存储
        return Base64.getEncoder().encodeToString(salt) + "$" +
                Base64.getEncoder().encodeToString(hash);
    }

    /**
     * 验证明文密码与加密密码是否匹配
     */
    public static boolean matches(String rawPassword, String encodedPassword) {
        try {
            String[] parts = encodedPassword.split("\\$");
            if (parts.length != 2) return false;

            byte[] salt = Base64.getDecoder().decode(parts[0]);
            byte[] expectedHash = Base64.getDecoder().decode(parts[1]);

            byte[] actualHash = hashPassword(rawPassword.getBytes(StandardCharsets.UTF_8), salt);

            return constantTimeArrayEquals(expectedHash, actualHash);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 内部方法：执行 Argon2 哈希
     */
    private static byte[] hashPassword(byte[] password, byte[] salt) {
        Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withSalt(salt)
                .withParallelism(PARALLELISM)
                .withMemoryAsKB(MEMORY_KB)
                .withIterations(ITERATIONS);

        Argon2BytesGenerator generator = new Argon2BytesGenerator();
        generator.init(builder.build());

        byte[] hash = new byte[HASH_LENGTH];
        generator.generateBytes(password, hash, 0, HASH_LENGTH);
        return hash;
    }

    /**
     * 安全的数组比较，防止时间攻击
     */
    private static boolean constantTimeArrayEquals(byte[] a, byte[] b) {
        if (a.length != b.length) return false;
        int result = 0;
        for (int i = 0; i < a.length; i++) {
            result |= a[i] ^ b[i];
        }
        return result == 0;
    }

    public static void main(String[] args) {
        // 生成加密密码
        String rawPassword = "Test123";
        String encodedPassword = encode(rawPassword);
        System.out.println("Encoded password: " + encodedPassword);

        boolean matches = matches(rawPassword, encodedPassword);
        System.out.println("Matches: " + matches);
    }
}
